<template><div><h2 id="laravel-pennant" tabindex="-1"><a class="header-anchor" href="#laravel-pennant"><span>Laravel Pennant</span></a></h2>
<ul>
<li><a href="#introduction">介绍</a></li>
<li><a href="#installation">安装</a></li>
<li><a href="#configuration">配置</a></li>
<li><a href="#defining-features">定义特性</a>
<ul>
<li><a href="#class-based-features">基于类的特性</a></li>
</ul>
</li>
<li><a href="#checking-features">检查特性</a>
<ul>
<li><a href="#conditional-execution">条件执行</a></li>
<li><a href="#the-has-features-trait">HasFeatures Trait</a></li>
<li><a href="#blade-directive">Blade 指令</a></li>
<li><a href="#middleware">中间件</a></li>
<li><a href="#in-memory-cache">内存缓存</a></li>
</ul>
</li>
<li><a href="#scope">作用域</a>
<ul>
<li><a href="#specifying-the-scope">指定作用域</a></li>
<li><a href="#default-scope">默认作用域</a></li>
<li><a href="#nullable-scope">空作用域</a></li>
<li><a href="#identifying-scope">标识作用域</a></li>
</ul>
</li>
<li><a href="#rich-feature-values">富特征值</a></li>
<li><a href="#retrieving-multiple-features">获取多个特性</a></li>
<li><a href="#eager-loading">预加载</a></li>
<li><a href="#updating-values">更新特征值</a>
<ul>
<li><a href="#bulk-updates">批量更新</a></li>
<li><a href="#purging-features">清除特性</a></li>
</ul>
</li>
<li><a href="#testing">测试</a></li>
<li><a href="#adding-custom-pennant-drivers">添加自定义 Pennant 驱动</a>
<ul>
<li><a href="#implementing-the-driver">实现驱动</a></li>
<li><a href="#registering-the-driver">注册驱动</a></li>
</ul>
</li>
<li><a href="#events">事件</a></li>
</ul>
<h2 id="介绍" tabindex="-1"><a class="header-anchor" href="#介绍"><span>介绍</span></a></h2>
<p><a href="https://github.com/laravel/pennant" target="_blank" rel="noopener noreferrer">Laravel Pennant</a> 是一个简单轻量的特性标志包，没有臃肿。特性标志使你可以有信心地逐步推出新的应用程序功能，测试新的界面设计，支持基干开发策略等等。</p>
<h2 id="安装" tabindex="-1"><a class="header-anchor" href="#安装"><span>安装</span></a></h2>
<p>首先，使用 Composer 包管理器将 Pennant 安装到你的项目中：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line"><span class="token function">composer</span> require laravel/pennant</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>接下来，你应该使用 <code v-pre>vendor:publish</code> Artisan 命令发布 Pennant 配置和迁移文件： <code v-pre>vendor:publish</code> Artisan command:</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan vendor:publish <span class="token parameter variable">--provider</span><span class="token operator">=</span><span class="token string">"Laravel\Pennant\PennantServiceProvider"</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>最后，你应该运行应用程序的数据库迁移。这将创建一个 <code v-pre>features</code> 表，<code v-pre>Pennant</code> 使用它来驱动其 <code v-pre>database</code> 驱动程序：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan migrate</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h2 id="配置" tabindex="-1"><a class="header-anchor" href="#配置"><span>配置</span></a></h2>
<p>在发布 Pennant 资源之后，配置文件将位于 <code v-pre>config/pennant.php</code>。此配置文件允许你指定 Pennant 用于存储已解析的特性标志值的默认存储机制。</p>
<p>Pennant 支持使用 <code v-pre>array</code> 驱动程序在内存数组中存储已解析的特性标志值。或者，Pennant 可以使用 <code v-pre>database</code> 驱动程序在关系数据库中持久存储已解析的特性标志值，这是 Pennant 使用的默认存储机制。</p>
<h2 id="定义特性" tabindex="-1"><a class="header-anchor" href="#定义特性"><span>定义特性</span></a></h2>
<p>要定义特性，你可以使用 <code v-pre>Feature</code> 门面提供的 <code v-pre>define</code> 方法。你需要为该特性提供一个名称以及一个闭包，用于解析该特性的初始值。</p>
<p>通常，特性是在服务提供程序中使用 <code v-pre>Feature</code> 门面定义的。闭包将接收特性检查的“作用域”。最常见的是，作用域是当前已认证的用户。在此示例中，我们将定义一个功能，用于逐步向应用程序用户推出新的 API：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Providers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Lottery</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>ServiceProvider</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">AppServiceProvider</span> <span class="token keyword">extends</span> <span class="token class-name">ServiceProvider</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * Bootstrap any application services.</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span> <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">match</span> <span class="token punctuation">(</span><span class="token constant boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">isInternalTeamMember</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">isHighTrafficCustomer</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token constant boolean">false</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token keyword">default</span> <span class="token operator">=></span> <span class="token class-name static-context">Lottery</span><span class="token operator">::</span><span class="token function">odds</span><span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator">/</span> <span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>正如你所看到的，我们对我们的特性有以下规则：</p>
<ul>
<li>所有内部团队成员应使用新 API。</li>
<li>任何高流量客户不应使用新 API。</li>
<li>否则，该特性应在具有 1/100 概率激活的用户中随机分配。</li>
</ul>
<p>首次检查给定用户的 <code v-pre>new-api</code>特性时，存储驱动程序将存储闭包的结果。下一次针对相同用户检查特性时，将从存储中检索该值，不会调用闭包。</p>
<p>为方便起见，如果特性定义仅返回一个 Lottery，你可以完全省略闭包：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'site-redesign'</span><span class="token punctuation">,</span> <span class="token class-name static-context">Lottery</span><span class="token operator">::</span><span class="token function">odds</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="基于类的特性" tabindex="-1"><a class="header-anchor" href="#基于类的特性"><span>基于类的特性</span></a></h3>
<p>Pennant 还允许你定义基于类的特性。不像基于闭包的特性定义，不需要在服务提供者中注册基于类的特性。为了创建一个基于类的特性，你可以调用 <code v-pre>pennant:feature</code> Artisan 命令。默认情况下，特性类将被放置在你的应用程序的 <code v-pre>app/Features</code> 目录中：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan pennant:feature NewApi</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>在编写特性类时，你只需要定义一个 <code v-pre>resolve</code> 方法，用于为给定的范围解析特性的初始值。同样，范围通常是当前经过身份验证的用户：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Features</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Lottery</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">NewApi</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 解析特性的初始值.</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">resolve</span><span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">mixed</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token keyword">match</span> <span class="token punctuation">(</span><span class="token constant boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">isInternalTeamMember</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">isHighTrafficCustomer</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token constant boolean">false</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token keyword">default</span> <span class="token operator">=></span> <span class="token class-name static-context">Lottery</span><span class="token operator">::</span><span class="token function">odds</span><span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator">/</span> <span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">}</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>注</strong> 特性类是通过<a href="https://learnku.com/docs/laravel/10.x/container" target="_blank" rel="noopener noreferrer">容器</a>,解析的，因此在需要时可以在特性类的构造函数中注入依赖项。</p>
</blockquote>
<h2 id="检查特性" tabindex="-1"><a class="header-anchor" href="#检查特性"><span>检查特性</span></a></h2>
<p>要确定一个特性是否处于活动状态，你可以在 <code v-pre>Feature</code> 门面上使用 <code v-pre>active</code> 方法。默认情况下，特性针对当前已认证的用户进行检查：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Response</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PodcastController</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 显示资源的列表.</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">index</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">Response</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">active</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token operator">?</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">resolveNewApiResponse</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token punctuation">:</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">resolveLegacyApiResponse</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>为了方便起见，如果一个特征定义只返回一个抽奖结果，你可以完全省略闭包:</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'site-redesign'</span><span class="token punctuation">,</span> <span class="token class-name static-context">Lottery</span><span class="token operator">::</span><span class="token function">odds</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="基于类的特征" tabindex="-1"><a class="header-anchor" href="#基于类的特征"><span>基于类的特征</span></a></h3>
<p>Pennant 还允许你定义基于类的特征。与基于闭包的特征定义不同，无需在服务提供者中注册基于类的特征。要创建基于类的特征，你可以调用 pennant:feature Artisan 命令。默认情况下，特征类将被放置在你的应用程序的 app/Features 目录中。:</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line">php artisan pennant<span class="token punctuation">:</span>feature NewApi</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>编写特征类时，你只需要定义一个 <code v-pre>resolve</code> 方法，该方法将被调用以解析给定作用域的特征的初始值。同样，该作用域通常是当前已验证的用户。:</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Features</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Lottery</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">NewApi</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 解析特征的初始值.</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">resolve</span><span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">mixed</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token keyword">match</span> <span class="token punctuation">(</span><span class="token constant boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">isInternalTeamMember</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">isHighTrafficCustomer</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token constant boolean">false</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token keyword">default</span> <span class="token operator">=></span> <span class="token class-name static-context">Lottery</span><span class="token operator">::</span><span class="token function">odds</span><span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator">/</span> <span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">}</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>注意</strong> 特征类通过 <a href="https://learnku.com/docs/laravel/10.x/container" target="_blank" rel="noopener noreferrer">容器</a>, 解析，因此在需要时，你可以将依赖项注入到特征类的构造函数中.</p>
</blockquote>
<h2 id="checking-features" tabindex="-1"><a class="header-anchor" href="#checking-features"><span>Checking Features</span></a></h2>
<p>要确定特征是否处于活动状态，你可以在 Feature 门面上使用 <code v-pre>active</code> 方法。默认情况下，特征将针对当前已验证的用户进行检查。:</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"></span>
<span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Response</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PodcastController</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     *显示资源的列表.</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">index</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">Response</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">active</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token operator">?</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">resolveNewApiResponse</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token punctuation">:</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">resolveLegacyApiResponse</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>虽然默认情况下特性针对当前已认证的用户进行检查，但你可以轻松地针对其他用户或范围检查特性。为此，使用 <code v-pre>Feature</code> 门面提供的 <code v-pre>for</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">return</span> <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">active</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">?</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">resolveNewApiResponse</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token punctuation">:</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">resolveLegacyApiResponse</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>Pennant 还提供了一些额外的方便方法，在确定特性是否活动或不活动时可能非常有用：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token comment">//确定所有给定的特性是否都活动...</span></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">allAreActive</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'site-redesign'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 确定任何给定的特性是否都活动...</span></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">someAreActive</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'site-redesign'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 确定特性是否处于非活动状态...</span></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">inactive</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 确定所有给定的特性是否都处于非活动状态...</span></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">allAreInactive</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'site-redesign'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 确定任何给定的特性是否都处于非活动状态...</span></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">someAreInactive</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'site-redesign'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p><strong>注</strong></p>
</blockquote>
<blockquote>
<p>当在 HTTP 上下文之外使用 Pennant（例如在 Artisan 命令或排队作业中）时，你通常应<a href="#specifying-the-scope">明确指定特性的作用域</a>。或者，你可以定义一个<a href="#default-scope">默认作用域</a>，该作用域考虑到已认证的 HTTP 上下文和未经身份验证的上下文。</p>
</blockquote>
<h4 id="检查基于类的特性" tabindex="-1"><a class="header-anchor" href="#检查基于类的特性"><span>检查基于类的特性</span></a></h4>
<p>对于基于类的特性，应该在检查特性时提供类名：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Features<span class="token punctuation">\</span>NewApi</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Response</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PodcastController</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line"></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 显示资源的列表.</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">index</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">Response</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">active</span><span class="token punctuation">(</span><span class="token class-name static-context">NewApi</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token operator">?</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">resolveNewApiResponse</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token punctuation">:</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">resolveLegacyApiResponse</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="条件执行" tabindex="-1"><a class="header-anchor" href="#条件执行"><span>条件执行</span></a></h3>
<p><code v-pre>when</code> 方法可用于在特性激活时流畅地执行给定的闭包。此外，可以提供第二个闭包，如果特性未激活，则将执行它：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Features<span class="token punctuation">\</span>NewApi</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Response</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PodcastController</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 显示资源的列表.</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">index</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">Response</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">when</span><span class="token punctuation">(</span><span class="token class-name static-context">NewApi</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">resolveNewApiResponse</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">resolveLegacyApiResponse</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><code v-pre>unless</code> 方法是 <code v-pre>when</code> 方法的相反，如果特性未激活，则执行第一个闭包：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">return</span> <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">unless</span><span class="token punctuation">(</span><span class="token class-name static-context">NewApi</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">resolveLegacyApiResponse</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">resolveNewApiResponse</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line"></span>
<span class="line"><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="hasfeatures-trait" tabindex="-1"><a class="header-anchor" href="#hasfeatures-trait"><span>HasFeatures Trait</span></a></h3>
<p>Pennant 的 <code v-pre>HasFeatures</code> Trait 可以添加到你的应用的 <code v-pre>User</code> 模型（或其他具有特性的模型）中，以提供一种流畅、方便的方式从模型直接检查特性：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"></span>
<span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Models</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Foundation<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>User</span> <span class="token keyword">as</span> Authenticatable<span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Concerns<span class="token punctuation">\</span>HasFeatures</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">User</span> <span class="token keyword">extends</span> <span class="token class-name">Authenticatable</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">use</span> <span class="token package">HasFeatures</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>一旦将 HasFeatures Trait 添加到你的模型中，你可以通过调用 <code v-pre>features</code> 方法轻松检查特性：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">features</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">active</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当然，<code v-pre>features</code> 方法提供了许多其他方便的方法来与特性交互：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token comment">// 值...</span></span>
<span class="line"><span class="token variable">$value</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">features</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">value</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">)</span></span>
<span class="line"><span class="token variable">$values</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">features</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">values</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 状态...</span></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">features</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">active</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">features</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">allAreActive</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'server-api'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">features</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">someAreActive</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'server-api'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">features</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">inactive</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">features</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">allAreInactive</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'server-api'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">features</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">someAreInactive</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'server-api'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 条件执行...</span></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">features</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">when</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token comment">/* ... */</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token comment">/* ... */</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">features</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">unless</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token comment">/* ... */</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token comment">/* ... */</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="blade-指令" tabindex="-1"><a class="header-anchor" href="#blade-指令"><span>Blade 指令</span></a></h3>
<p>为了使在 Blade 中检查特性的体验更加流畅，Pennant提供了一个 <code v-pre>@feature</code> 指令：</p>
<div class="language-blade line-numbers-mode" data-highlighter="prismjs" data-ext="blade" data-title="blade"><pre v-pre class="language-blade"><code><span class="line">@feature('site-redesign')</span>
<span class="line">&lt;!-- 'site-redesign' 活跃中 --&gt;</span>
<span class="line">@else</span>
<span class="line">&lt;!-- 'site-redesign' 不活跃--&gt;</span>
<span class="line">@endfeature</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="中间件" tabindex="-1"><a class="header-anchor" href="#中间件"><span>中间件</span></a></h3>
<p>Pennant 还包括一个<a href="https://learnku.com/docs/laravel/10.x/middleware" target="_blank" rel="noopener noreferrer">中间件</a>，它可以在路由调用之前验证当前认证用户是否有访问功能的权限。首先，你应该将 <code v-pre>EnsureFeaturesAreActive</code> 中间件的别名添加到你的应用程序的 <code v-pre>app/Http/Kernel.php</code> 文件中：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Middleware<span class="token punctuation">\</span>EnsureFeaturesAreActive</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">protected</span> <span class="token variable">$middlewareAliases</span> <span class="token operator">=</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"> <span class="token string single-quoted-string">'features'</span> <span class="token operator">=></span> <span class="token class-name static-context">EnsureFeaturesAreActive</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>接下来，你可以将中间件分配给一个路由并指定需要访问该路由的功能。如果当前认证用户的任何指定功能未激活，则路由将返回 <code v-pre>400 Bad Request</code> HTTP 响应。可以使用逗号分隔的列表指定多个功能：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/api/servers'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'features:new-api,servers-api'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="自定义响应" tabindex="-1"><a class="header-anchor" href="#自定义响应"><span>自定义响应</span></a></h4>
<p>如果你希望在未激活列表中的任何一个功能时自定义中间件返回的响应，可以使用 <code v-pre>EnsureFeaturesAreActive</code> 中间件提供的 <code v-pre>whenInactive</code> 方法。通常，这个方法应该在应用程序的服务提供者的 boot 方法中调用：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Response</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Middleware<span class="token punctuation">\</span>EnsureFeaturesAreActive</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 加载服务.</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">EnsureFeaturesAreActive</span><span class="token operator">::</span><span class="token function">whenInactive</span><span class="token punctuation">(</span></span>
<span class="line">        <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token keyword type-hint">array</span> <span class="token variable">$features</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Response</span><span class="token punctuation">(</span><span class="token argument-name">status</span><span class="token punctuation">:</span> <span class="token number">403</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token punctuation">}</span></span>
<span class="line">    <span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="内存缓存" tabindex="-1"><a class="header-anchor" href="#内存缓存"><span>内存缓存</span></a></h3>
<p>当检查特性时，Pennant 将创建一个内存缓存以存储结果。如果你使用的是 <code v-pre>database</code> 驱动程序，则在单个请求中重新检查相同的功能标志将不会触发额外的数据库查询。这也确保了该功能在请求的持续时间内具有一致的结果。</p>
<p>如果你需要手动刷新内存缓存，可以使用 <code v-pre>Feature</code> 门面提供的 <code v-pre>flushCache</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">flushCache</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h2 id="作用域" tabindex="-1"><a class="header-anchor" href="#作用域"><span>作用域</span></a></h2>
<h3 id="指定作用域" tabindex="-1"><a class="header-anchor" href="#指定作用域"><span>指定作用域</span></a></h3>
<p>如前所述，特性通常会针对当前已验证的用户进行检查。但这可能并不总是适合你的需求。因此，你可以通过 <code v-pre>Feature</code> 门面的 <code v-pre>for</code> 方法来指定要针对哪个作用域检查给定的特性：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">return</span> <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">active</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token operator">?</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">resolveNewApiResponse</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span></span>
<span class="line">        <span class="token punctuation">:</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">resolveLegacyApiResponse</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当然，特性作用域不限于“用户”。假设你构建了一个新的结算体验，你要将其推出给整个团队而不是单个用户。也许你希望年龄最大的团队的推出速度比年轻的团队慢。你的特性解析闭包可能如下所示：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>Team</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Carbon<span class="token punctuation">\</span>Carbon</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Lottery</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'billing-v2'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Team</span> <span class="token variable">$team</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$team</span><span class="token operator">-></span><span class="token property">created_at</span><span class="token operator">-></span><span class="token function">isAfter</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Carbon</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'1st Jan, 2023'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token constant boolean">true</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$team</span><span class="token operator">-></span><span class="token property">created_at</span><span class="token operator">-></span><span class="token function">isAfter</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Carbon</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'1st Jan, 2019'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token class-name static-context">Lottery</span><span class="token operator">::</span><span class="token function">odds</span><span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator">/</span> <span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token class-name static-context">Lottery</span><span class="token operator">::</span><span class="token function">odds</span><span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator">/</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你会注意到，我们定义的闭包不需要 <code v-pre>User</code>，而是需要一个 <code v-pre>Team</code> 模型。要确定该特性是否对用户的团队可用，你应该将团队传递给 <code v-pre>Feature</code> 门面提供的 <code v-pre>for</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token property">team</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">active</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'billing-v2'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">to</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/billing/v2'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"><span class="token comment">// ...</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="默认作用域" tabindex="-1"><a class="header-anchor" href="#默认作用域"><span>默认作用域</span></a></h3>
<p>还可以自定义 Pennant 用于检查特性的默认作用域。例如，你可能希望所有特性都针对当前认证用户的团队进行检查，而不是针对用户。你可以在应用程序的服务提供程序中指定此作用域。通常，应该在一个应用程序的服务提供程序中完成这个过程:</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Providers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Auth</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>ServiceProvider</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">AppServiceProvider</span> <span class="token keyword">extends</span> <span class="token class-name">ServiceProvider</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 加载程序服务.</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">resolveScopeUsing</span><span class="token punctuation">(</span><span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token variable">$driver</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token class-name static-context">Auth</span><span class="token operator">::</span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">?-></span><span class="token property">team</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token comment">// ...</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果没有通过 <code v-pre>for</code> 方法显式提供作用域，则特性检查将使用当前认证用户的团队作为默认作用域：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">active</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'billing-v2'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 目前等价于...</span></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token property">team</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">active</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'billing-v2'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="空作用域" tabindex="-1"><a class="header-anchor" href="#空作用域"><span>空作用域</span></a></h3>
<p>如果你检查特性时提供的作用域范围为 <code v-pre>null</code>，且特性定义中不支持 <code v-pre>null</code>（即不是 nullable type 或者没有在 union type 中包含<code v-pre>null</code>），那么 Pennant 将自动返回 <code v-pre>false</code> 作为特性的结果值。</p>
<p>因此，如果你传递给特性的作用域可能为 null 并且你想要特性值的解析器被调用，你应该在特性定义逻辑中处理 <code v-pre>null</code> 范围值。在一个 Artisan 命令、排队作业或未经身份验证的路由中检查特性可能会出现 <code v-pre>null</code> 作用域。因为在这些情况下通常没有经过身份验证的用户，所以默认的作用域将为 <code v-pre>null</code>。</p>
<p>如果你不总是<a href="#specifying-the-scope">明确指定特性作用域</a>，则应确保范围类型为”nullable”，并在特性定义逻辑中处理 <code v-pre>null</code> 范围值:</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Models<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Lottery</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span> <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">match</span> <span class="token punctuation">(</span><span class="token constant boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">// [tl! remove]</span></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span> <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token class-name">User</span><span class="token operator">|</span><span class="token keyword type-declaration">null</span> <span class="token variable">$user</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">match</span> <span class="token punctuation">(</span><span class="token constant boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">// [tl! add]</span></span>
<span class="line">    <span class="token variable">$user</span> <span class="token operator">===</span> <span class="token constant">null</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">,</span><span class="token comment">// [tl! add]</span></span>
<span class="line">    <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">isInternalTeamMember</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token constant boolean">true</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">isHighTrafficCustomer</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token constant boolean">false</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">default</span> <span class="token operator">=></span> <span class="token class-name static-context">Lottery</span><span class="token operator">::</span><span class="token function">odds</span><span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator">/</span> <span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="标识作用域" tabindex="-1"><a class="header-anchor" href="#标识作用域"><span>标识作用域</span></a></h3>
<p>Pennant 的内置 <code v-pre>array</code> 和 <code v-pre>database</code> 存储驱动程序可以正确地存储所有 PHP 数据类型以及 Eloquent 模型的作用域标识符。但是，如果你的应用程序使用第三方的 Pennant 驱动程序，该驱动程序可能不知道如何正确地存储 Eloquent 模型或应用程序中其他自定义类型的标识符。</p>
<p>因此，Pennant 允许你通过在应用程序中用作 Pennant 作用域的对象上实现 <code v-pre>FeatureScopeable</code> 协议来格式化存储范围值。</p>
<p>例如，假设你在单个应用程序中使用了两个不同的特性驱动程序：内置 <code v-pre>database</code> 驱动程序和第三方的“Flag Rocket”驱动程序。 “Flag Rocket”驱动程序不知道如何正确地存储 Eloquent 模型。相反，它需要一个<code v-pre>FlagRocketUser</code> 实例。通过实现 <code v-pre>FeatureScopeable</code> 协议中的 <code v-pre>toFeatureIdentifier</code> 方法，我们可以自定义提供给应用程序中每个驱动程序的可存储范围值：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Models</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">FlagRocket<span class="token punctuation">\</span>FlagRocketUser</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Database<span class="token punctuation">\</span>Eloquent<span class="token punctuation">\</span>Model</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Contracts<span class="token punctuation">\</span>FeatureScopeable</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">User</span> <span class="token keyword">extends</span> <span class="token class-name">Model</span> <span class="token keyword">implements</span> <span class="token class-name">FeatureScopeable</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 将对象强制转换为给定驱动程序的功能范围标识符.</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">toFeatureIdentifier</span><span class="token punctuation">(</span><span class="token keyword type-hint">string</span> <span class="token variable">$driver</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">mixed</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token keyword">match</span><span class="token punctuation">(</span><span class="token variable">$driver</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">         <span class="token string single-quoted-string">'database'</span> <span class="token operator">=></span> <span class="token variable">$this</span><span class="token punctuation">,</span></span>
<span class="line">         <span class="token string single-quoted-string">'flag-rocket'</span> <span class="token operator">=></span> <span class="token class-name static-context">FlagRocketUser</span><span class="token operator">::</span><span class="token function">fromId</span><span class="token punctuation">(</span><span class="token variable">$this</span><span class="token operator">-></span><span class="token property">flag_rocket_id</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">}</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="丰富的特征值" tabindex="-1"><a class="header-anchor" href="#丰富的特征值"><span>丰富的特征值</span></a></h2>
<p>到目前为止，我们主要展示了特性的二进制状态，即它们是「活动的」还是「非活动的」，但是 Pennant 也允许你存储丰富的值。</p>
<p>例如，假设你正在测试应用程序的「立即购买」按钮的三种新颜色。你可以从特性定义中返回一个字符串，而不是 <code v-pre>true</code> 或 <code v-pre>false</code>：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Arr</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">,</span> <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token class-name static-context">Arr</span><span class="token operator">::</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line"> <span class="token string single-quoted-string">'blue-sapphire'</span><span class="token punctuation">,</span></span>
<span class="line"> <span class="token string single-quoted-string">'seafoam-green'</span><span class="token punctuation">,</span></span>
<span class="line"> <span class="token string single-quoted-string">'tart-orange'</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你可以使用 <code v-pre>value</code> 方法检索 <code v-pre>purchase-button</code> 特性的值：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$color</span> <span class="token operator">=</span> <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>Pennant 提供的 Blade 指令也使得根据特性的当前值条件性地呈现内容变得容易：</p>
<div class="language-blade line-numbers-mode" data-highlighter="prismjs" data-ext="blade" data-title="blade"><pre v-pre class="language-blade"><code><span class="line">@feature('purchase-button', 'blue-sapphire')</span>
<span class="line">&lt;!-- 'blue-sapphire' is active --&gt;</span>
<span class="line">@elsefeature('purchase-button', 'seafoam-green')</span>
<span class="line">&lt;!-- 'seafoam-green' is active --&gt;</span>
<span class="line">@elsefeature('purchase-button', 'tart-orange')</span>
<span class="line">&lt;!-- 'tart-orange' is active --&gt;</span>
<span class="line">@endfeature</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p>使用丰富值时，重要的是要知道，只要特性具有除 <code v-pre>false</code> 以外的任何值，它就被视为「活动」。</p>
</blockquote>
<p>在调用<a href="#conditional-execution">条件</a> <code v-pre>when</code> 方法时，特性的丰富值将提供给第一个闭包：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">when</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token variable">$color</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token comment">/* ... */</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token comment">/* ... */</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>同样，当调用条件 <code v-pre>unless</code> 方法时，特性的丰富值将提供给可选的第二个闭包：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">unless</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token comment">/* ... */</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token variable">$color</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token comment">/* ... */</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="获取多个特性" tabindex="-1"><a class="header-anchor" href="#获取多个特性"><span>获取多个特性</span></a></h2>
<p><code v-pre>values</code> 方法允许检索给定作用域的多个特征：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">values</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'billing-v2'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// [</span></span>
<span class="line"><span class="token comment">// 'billing-v2' => false,</span></span>
<span class="line"><span class="token comment">// 'purchase-button' => 'blue-sapphire',</span></span>
<span class="line"><span class="token comment">// ]</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>或者，你可以使用 <code v-pre>all</code> 方法检索给定范围内所有已定义功能的值：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">all</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// [</span></span>
<span class="line"><span class="token comment">// 'billing-v2' => false,</span></span>
<span class="line"><span class="token comment">// 'purchase-button' => 'blue-sapphire',</span></span>
<span class="line"><span class="token comment">// 'site-redesign' => true,</span></span>
<span class="line"><span class="token comment">// ]</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>但是，基于类的功能是动态注册的，直到它们被显式检查之前，Pennant并不知道它们的存在。这意味着，如果在当前请求期间尚未检查过应用程序的基于类的功能，则这些功能可能不会出现在 <code v-pre>all</code> 方法返回的结果中。</p>
<p>如果你想确保使用 <code v-pre>all</code> 方法时始终包括功能类，你可以使用Pennant的功能发现功能。要开始使用，请在你的应用程序的任何服务提供程序之一中调用 <code v-pre>discover</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Providers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>ServiceProvider</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">AppServiceProvider</span> <span class="token keyword">extends</span> <span class="token class-name">ServiceProvider</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * Bootstrap any application services.</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">discover</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token comment">// ...</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><code v-pre>discover</code> 方法将注册应用程序 <code v-pre>app/Features</code> 目录中的所有功能类。<code v-pre>all</code> 方法现在将在其结果中包括这些类，无论它们是否在当前请求期间进行了检查：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">all</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// [</span></span>
<span class="line"><span class="token comment">// 'App\Features\NewApi' => true,</span></span>
<span class="line"><span class="token comment">// 'billing-v2' => false,</span></span>
<span class="line"><span class="token comment">// 'purchase-button' => 'blue-sapphire',</span></span>
<span class="line"><span class="token comment">// 'site-redesign' => true,</span></span>
<span class="line"><span class="token comment">// ]</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="预加载" tabindex="-1"><a class="header-anchor" href="#预加载"><span>预加载</span></a></h2>
<p>尽管 Pennant 在单个请求中保留了所有已解析功能的内存缓存，但仍可能遇到性能问题。为了缓解这种情况，Pennant 提供了预加载功能。</p>
<p>为了说明这一点，想象一下我们正在循环中检查功能是否处于活动状态：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token variable">$users</span> <span class="token keyword">as</span> <span class="token variable">$user</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">active</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'notifications-beta'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">notify</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">RegistrationSuccess</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>假设我们正在使用数据库驱动程序，此代码将为循环中的每个用户执行数据库查询-执行潜在的数百个查询。但是，使用 Pennant 的 <code v-pre>load</code> 方法，我们可以通过预加载一组用户或作用域的功能值来消除这种潜在的性能瓶颈：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token variable">$users</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">load</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'notifications-beta'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token variable">$users</span> <span class="token keyword">as</span> <span class="token variable">$user</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">active</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'notifications-beta'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">notify</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">RegistrationSuccess</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>为了仅在尚未加载功能值时加载它们，你可以使用 <code v-pre>loadMissing</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token variable">$users</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">loadMissing</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line"> <span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span></span>
<span class="line"> <span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">,</span></span>
<span class="line"> <span class="token string single-quoted-string">'notifications-beta'</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="更新值" tabindex="-1"><a class="header-anchor" href="#更新值"><span>更新值</span></a></h2>
<p>当首次解析功能的值时，底层驱动程序将把结果存储在存储中。这通常是为了确保在请求之间为你的用户提供一致的体验。但是，有时你可能想手动更新功能的存储值。</p>
<p>为了实现这一点，你可以使用 <code v-pre>activate</code> 和 <code v-pre>deactivate</code> 方法来切换功能的 「打开」或「关闭」状态：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 激活默认作用域的功能...</span></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">activate</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 在给定的范围中停用功能...</span></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token property">team</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">deactivate</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'billing-v2'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>还可以通过向 <code v-pre>activate</code> 方法提供第二个参数来手动设置功能的丰富值：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">activate</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'seafoam-green'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>要指示 Pennant 忘记功能的存储值，你可以使用 <code v-pre>forget</code> 方法。当再次检查功能时，Pennant 将从其功能定义中解析功能的值：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">forget</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><h3 id="批量更新" tabindex="-1"><a class="header-anchor" href="#批量更新"><span>批量更新</span></a></h3>
<p>要批量更新存储的功能值，你可以使用 <code v-pre>activateForEveryone</code> 和 <code v-pre>deactivateForEveryone</code> 方法。</p>
<p>例如，假设你现在对 <code v-pre>new-api</code> 功能的稳定性有信心，并为结帐流程找到了最佳的「purchase-button」颜色-你可以相应地更新所有用户的存储值：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">activateForEveryone</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">activateForEveryone</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'seafoam-green'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>或者，你可以停用所有用户的该功能：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">deactivateForEveryone</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><blockquote>
<p>**注意：**这将仅更新已由 Pennant 存储驱动程序存储的已解析功能值。你还需要更新应用程序中的功能定义。</p>
</blockquote>
<h3 id="清除功能" tabindex="-1"><a class="header-anchor" href="#清除功能"><span>清除功能</span></a></h3>
<p>有时，清除存储中的整个功能可以非常有用。如果你已从应用程序中删除了功能或已对功能的定义进行了调整，并希望将其部署到所有用户，则通常需要这样做。</p>
<p>你可以使用 <code v-pre>purge</code> 方法删除功能的所有存储值：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token comment">// 清除单个功能...</span></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">purge</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 清除多个功能...</span></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">purge</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'new-api'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你想从存储中清除所有功能，则可以调用 <code v-pre>purge</code> 方法而不带任何参数：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">purge</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>由于在应用程序的部署流程中清除功能可能非常有用，因此 Pennant 包括一个<code v-pre>pennant:purge</code> Artisan命令：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">php artisan pennant:purge new-api</span>
<span class="line">php artisan pennant:purge new-api purchase-button</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="测试" tabindex="-1"><a class="header-anchor" href="#测试"><span>测试</span></a></h2>
<p>当测试与功能标志交互的代码时，控制测试中返回的功能标志的最简单方法是简单地重新定义该功能。例如，假设你在应用程序的一个服务提供程序中定义了以下功能：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Arr</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">,</span> <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token class-name static-context">Arr</span><span class="token operator">::</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">[</span></span>
<span class="line"> <span class="token string single-quoted-string">'blue-sapphire'</span><span class="token punctuation">,</span></span>
<span class="line"> <span class="token string single-quoted-string">'seafoam-green'</span><span class="token punctuation">,</span></span>
<span class="line"> <span class="token string single-quoted-string">'tart-orange'</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>要在测试中修改功能的返回值，你可以在测试开始时重新定义该功能。以下测试将始终通过，即使 <code v-pre>Arr::random()</code> 实现仍然存在于服务提供程序中：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">test_it_can_control_feature_values</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'seafoam-green'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">assertSame</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'seafoam-green'</span><span class="token punctuation">,</span> <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'purchase-button'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>相同的方法也可以用于基于类的功能：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Features<span class="token punctuation">\</span>NewApi</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">test_it_can_control_feature_values</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token class-name static-context">NewApi</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token constant boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">assertTrue</span><span class="token punctuation">(</span><span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token class-name static-context">NewApi</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你的功能返回一个 <code v-pre>Lottery</code> 实例，那么有一些有用的<a href="https://learnku.com/docs/laravel/10.x/helpers#testing-lotteries" target="_blank" rel="noopener noreferrer">测试辅助函数可用</a>。</p>
<h4 id="存储配置" tabindex="-1"><a class="header-anchor" href="#存储配置"><span>存储配置</span></a></h4>
<p>你可以通过在应用程序的 <code v-pre>phpunit.xml</code> 文件中定义 <code v-pre>PENNANT_STORE</code> 环境变量来配置 Pennant 在测试期间使用的存储：</p>
<div class="language-xml line-numbers-mode" data-highlighter="prismjs" data-ext="xml" data-title="xml"><pre v-pre class="language-xml"><code><span class="line"><span class="token prolog">&lt;?xml version="1.0"  encoding="UTF-8"?></span></span>
<span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>phpunit</span> <span class="token attr-name">colors</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></span>
<span class="line">    <span class="token comment">&lt;!-- ... --></span></span>
<span class="line">    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>php</span><span class="token punctuation">></span></span></span>
<span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>env</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>PENNANT_STORE<span class="token punctuation">"</span></span>  <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>array<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span></span>
<span class="line">        <span class="token comment">&lt;!-- ... --></span></span>
<span class="line">    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>php</span><span class="token punctuation">></span></span></span>
<span class="line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>phpunit</span><span class="token punctuation">></span></span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="添加自定义pennant驱动程序" tabindex="-1"><a class="header-anchor" href="#添加自定义pennant驱动程序"><span>添加自定义Pennant驱动程序</span></a></h2>
<h4 id="实现驱动程序" tabindex="-1"><a class="header-anchor" href="#实现驱动程序"><span>实现驱动程序</span></a></h4>
<p>如果 Pennant 现有的存储驱动程序都不符合你的应用程序需求，则可以编写自己的存储驱动程序。你的自定义驱动程序应实现 <code v-pre>Laravel\Pennant\Contracts\Driver</code> 接口：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Extensions</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Contracts<span class="token punctuation">\</span>Driver</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">RedisFeatureDriver</span> <span class="token keyword">implements</span> <span class="token class-name">Driver</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">define</span><span class="token punctuation">(</span><span class="token keyword type-hint">string</span> <span class="token variable">$feature</span><span class="token punctuation">,</span> <span class="token keyword type-hint">callable</span> <span class="token variable">$resolver</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">defined</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">array</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">getAll</span><span class="token punctuation">(</span><span class="token keyword type-hint">array</span> <span class="token variable">$features</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">array</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">get</span><span class="token punctuation">(</span><span class="token keyword type-hint">string</span> <span class="token variable">$feature</span><span class="token punctuation">,</span> <span class="token keyword type-hint">mixed</span> <span class="token variable">$scope</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">mixed</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">set</span><span class="token punctuation">(</span><span class="token keyword type-hint">string</span> <span class="token variable">$feature</span><span class="token punctuation">,</span> <span class="token keyword type-hint">mixed</span> <span class="token variable">$scope</span><span class="token punctuation">,</span> <span class="token keyword type-hint">mixed</span> <span class="token variable">$value</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">setForAllScopes</span><span class="token punctuation">(</span><span class="token keyword type-hint">string</span> <span class="token variable">$feature</span><span class="token punctuation">,</span> <span class="token keyword type-hint">mixed</span> <span class="token variable">$value</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">delete</span><span class="token punctuation">(</span><span class="token keyword type-hint">string</span> <span class="token variable">$feature</span><span class="token punctuation">,</span> <span class="token keyword type-hint">mixed</span> <span class="token variable">$scope</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">purge</span><span class="token punctuation">(</span><span class="token keyword type-declaration">array</span><span class="token operator">|</span><span class="token keyword type-declaration">null</span> <span class="token variable">$features</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>现在，我们只需要使用 Redis 连接实现这些方法。可以在 <a href="https://github.com/laravel/pennant/blob/1.x/src/Drivers/DatabaseDriver.php" target="_blank" rel="noopener noreferrer">Pennant</a> 源代码中查看如何实现这些方法的示例。</p>
<blockquote>
<p><strong>注意</strong></p>
</blockquote>
<blockquote>
<p>Laravel 不附带包含扩展的目录。你可以自由地将它们放在任何你喜欢的位置。在这个示例中，我们创建了一个 <code v-pre>Extensions</code> 目录来存放 <code v-pre>RedisFeatureDriver</code>。</p>
</blockquote>
<h4 id="注册驱动" tabindex="-1"><a class="header-anchor" href="#注册驱动"><span>注册驱动</span></a></h4>
<p>一旦你的驱动程序被实现，就可以将其注册到 Laravel 中。要向 Pennant 添加其他驱动程序，可以使用 <code v-pre>Feature</code> 门面提供的 <code v-pre>extend</code> 方法。应该在应用程序的 <a href="https://learnku.com/docs/laravel/10.x/providers" target="_blank" rel="noopener noreferrer">服务提供者</a> 的 <code v-pre>boot</code> 方法中调用 <code v-pre>extend</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Providers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Extensions<span class="token punctuation">\</span>RedisFeatureDriver</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Contracts<span class="token punctuation">\</span>Foundation<span class="token punctuation">\</span>Application</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>ServiceProvider</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Feature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">AppServiceProvider</span> <span class="token keyword">extends</span> <span class="token class-name">ServiceProvider</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 注册任何应用程序服务。</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">register</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token comment">// ...</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 引导任何应用程序服务。</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token class-name static-context">Feature</span><span class="token operator">::</span><span class="token function">extend</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'redis'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Application</span> <span class="token variable">$app</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">RedisFeatureDriver</span><span class="token punctuation">(</span><span class="token variable">$app</span><span class="token operator">-></span><span class="token function">make</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'redis'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token variable">$app</span><span class="token operator">-></span><span class="token function">make</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'events'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>一旦驱动程序被注册，就可以在应用程序的 <code v-pre>config/pennant.php</code> 配置文件中使用 <code v-pre>redis</code> 驱动程序：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token string single-quoted-string">'stores'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'redis'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'driver'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'redis'</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token string single-quoted-string">'connection'</span> <span class="token operator">=></span> <span class="token constant">null</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="事件" tabindex="-1"><a class="header-anchor" href="#事件"><span>事件</span></a></h2>
<p>Pennant 分发了各种事件，这些事件在跟踪应用程序中的特性标志时非常有用。</p>
<h3 id="laravel-pennant-events-retrievingknownfeature" tabindex="-1"><a class="header-anchor" href="#laravel-pennant-events-retrievingknownfeature"><span><code v-pre>Laravel\Pennant\Events\RetrievingKnownFeature</code></span></a></h3>
<p>该事件在请求特定作用域的已知特征值第一次被检索时被触发。此事件可用于创建和跟踪应用程序中使用的特征标记的度量标准。</p>
<h3 id="laravel-pennant-events-retrievingunknownfeature" tabindex="-1"><a class="header-anchor" href="#laravel-pennant-events-retrievingunknownfeature"><span><code v-pre>Laravel\Pennant\Events\RetrievingUnknownFeature</code></span></a></h3>
<p>当在请求特定作用域的情况下第一次检索未知特性时，将分派此事件。如果你打算从应用程序中删除功能标志，但可能在整个应用程序中留下了某些零散的引用，此事件可能会有用。你可能会发现有用的是监听此事件并在其发生时 <code v-pre>report</code> 或抛出异常：</p>
<p>例如，你可能会发现在监听到此事件并出现此情况时，使用 <code v-pre>report</code> 或引发异常会很有用：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Providers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Foundation<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Providers<span class="token punctuation">\</span>EventServiceProvider</span> <span class="token keyword">as</span> ServiceProvider<span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Event</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation">\</span>Pennant<span class="token punctuation">\</span>Events<span class="token punctuation">\</span>RetrievingUnknownFeature</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">EventServiceProvider</span> <span class="token keyword">extends</span> <span class="token class-name">ServiceProvider</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * Register any other events for your application.</span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token class-name static-context">Event</span><span class="token operator">::</span><span class="token function">listen</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">RetrievingUnknownFeature</span> <span class="token variable">$event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">            <span class="token function">report</span><span class="token punctuation">(</span><span class="token string double-quoted-string">"Resolving unknown feature [<span class="token interpolation"><span class="token punctuation">{</span><span class="token variable">$event</span><span class="token operator">-></span><span class="token property">feature</span><span class="token punctuation">}</span></span>]."</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="laravel-pennant-events-dynamicallydefiningfeature" tabindex="-1"><a class="header-anchor" href="#laravel-pennant-events-dynamicallydefiningfeature"><span><code v-pre>Laravel\Pennant\Events\DynamicallyDefiningFeature</code></span></a></h3>
<p>当在请求期间首次动态检查基于类的特性时，将分派此事件。</p>
<blockquote>
<p>本译文仅用于学习和交流目的，转载请务必注明文章译者、出处、和本文链接<br>
我们的翻译工作遵照 <a href="https://learnku.com/docs/guide/cc4.0/6589" target="_blank" rel="noopener noreferrer">CC 协议</a>，如果我们的工作有侵犯到您的权益，请及时联系我们。</p>
</blockquote>
<hr>
<blockquote>
<p>原文地址：<a href="https://learnku.com/docs/laravel/10.x/pennant/14911" target="_blank" rel="noopener noreferrer">https://learnku.com/docs/laravel/10.x/pe...</a></p>
<p>译文地址：<a href="https://learnku.com/docs/laravel/10.x/pennant/14911" target="_blank" rel="noopener noreferrer">https://learnku.com/docs/laravel/10.x/pe...</a></p>
</blockquote>
</div></template>


